package com.sb.crawler.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gargoylesoftware.htmlunit.ScriptResult;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.sb.async.AsyncTaskService;
import com.sb.callback.CallBack;
import com.sb.configtion.SpringUtil;
import com.sb.crawler.BaseCrawler;
import com.sb.entity.ActionContext;
import com.sb.entity.Result;
import com.sb.entity.SBContext;
import com.sb.enums.StateCodeEnum;
import com.sb.net.Client;
import com.sb.parse.impl.ZheJiangZWService;
import com.sb.utils.FileUtils;
import com.sb.utils.Regex;
import com.sb.utils.Utils;
import okhttp3.Request;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;



/**
 * 浙江政务网
 * Created by wujunzhou on 2017/10/16.
 */
//@Service
public class ZheJiangZW implements BaseCrawler {
    private  final Logger logger= LoggerFactory.getLogger(ZheJiangZW.class);

//    @Resource
    private ZheJiangZWService zheJiangZWService ;
    private SBContext sbContext = new SBContext();
    public static final String LIMIT = "500";
    public static final WebClient WEBCLIENT = new WebClient();
    private Client client = new Client();
    private String appkey = "";
    private String cityCode = "";
    private JSONArray entrys;
    private AsyncTaskService asyncTaskService;

    Map<String, String> map = new HashMap<>();

    public ZheJiangZW(String cityCode) {
        this.zheJiangZWService = SpringUtil.getBean("zheJiangZWService",ZheJiangZWService.class);
        this.asyncTaskService = SpringUtil.getBean("asyncTaskService",AsyncTaskService.class);
        this.cityCode = cityCode;
    }

    public SBContext getSbContext() {
        return sbContext;
    }

    @Override
    public String login(ActionContext actionContext) {
        map.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");

        String retStr = client.doGetRequest("https://puser.zjzwfw.gov.cn/sso/usp.do?action=ssoLogin&servicecode=njdh",map);

        retStr = client.doPostRequest("https://puser.zjzwfw.gov.cn/sso/usp.do","action=publickey",map);
        String key = Regex.regexStr(retStr, "key\":\"(.*?)\"");
        String ePwd = null;
        try {
            ePwd = encode(actionContext.getPassword(), key);
        } catch (Exception e) {
            logger.info("encode err,Msg:" + e.getMessage());
            return "-999";
        }

        retStr = client.doPostRequest("https://puser.zjzwfw.gov.cn/sso/usp.do?rd=" + Math.random(),"action=ssoValidate&isusp=0&loginname=" + actionContext.getUsername() + "&loginpwd=" + Utils.urlEncode(actionContext.getPassword(), "gb18030") + "&servicecode=njdh&verifycode=" + actionContext.getCaptcha(),map);
        //校验是否登录成功
        if (!Regex.isMatch(retStr, "\\S*?-ticket")) {
            logger.info("登录失败1: "+retStr);
            return retStr;
        }
        //登录成功 进行跨域
        retStr = client.doGetRequest("https://puser.zjzwfw.gov.cn/sso/usp.do?1=1&action=redirect&ticket=" + retStr,map);

        retStr = client.doGetRequest("http://www.zjzwfw.gov.cn/zjzw/member/login/userresultNew.do?webId=1854&callback=jsload&rand=" + Math.random(),map);


        retStr = client.doGetRequest("http://puser.zjzwfw.gov.cn/sso/usp.do?action=ssoLogin&servicecode=njdh&goto=http%3a%2f%2fpuser.zjzwfw.gov.cn%2fsso%2fusp.do%3faction%3dzfRedirect%26servicecode%3drlsbcx&webId=1&tabid=00001",map);
        String appid = Regex.regexStr(retStr, "appid.*?value=\"(.*?)\"");


        String ticket = client.doPostRequest("https://puser.zjzwfw.gov.cn/sso/usp.do","action=getTicket&appid=" + appid,map);
        if (!Regex.isMatch(ticket, "\\S*?-ticket")) {
            logger.info("隐式登录失败1: "+retStr);
            return ticket;
        }
        retStr = client.doPostRequest("https://puser.zjzwfw.gov.cn/sso/usp.do","action=publickey",map);


        retStr = client.doGetRequest("https://puser.zjzwfw.gov.cn/sso/usp.do?action=redirect&ticket=" + ticket + "&goto=http%3A//puser.zjzwfw.gov.cn/sso/usp.do%3Faction%3DzfRedirect%26servicecode%3Drlsbcx",map);
        if (retStr.contains("账号认证")){
            return "-998";
        }
        retStr = client.doGetRequest("http://sbcx.pcyyhj.zjzwfw.gov.cn/proxy/html/" + cityCode + "/entry.html?" + System.currentTimeMillis(),map);
        if (!retStr.contains("sbcx-type")) return "-999";
//        Document parse = Jsoup.parse(retStr);
//        parse.
        entrys = getEntrys(retStr);
        logger.info("登录成功");
        return "0";
    }
//    @Async
    @Override
    public boolean sbcx(ActionContext actionContext) {
        entrys.forEach((Object entry) -> {
            JSONObject jso = (JSONObject) entry;
            String key = jso.getString("key");
            String title = jso.getString("title");
            JSONArray datasets = jso.getJSONArray("dataset");
            doCrawler(actionContext, key, title, datasets);
        });
        try {
            ObjectMapper mapper = new ObjectMapper();
            sbContext.getAccount().setUserId(actionContext.getUser().getUserId());
            sbContext.getAccount().setUserSource(actionContext.getUser().getUserSource());
            sbContext.getAccount().setSessionId(actionContext.getUser().getSessionId());
            String json = mapper.writeValueAsString(sbContext);
            logger.info("解析成功："+json);
            FileUtils.save("parse",json);
            CallBack.postData(json);
            logger.info("[end] ");
        } catch (JsonProcessingException e) {
            logger.info("json 转化失败",e);
        }
        return false;
    }
    private void doCrawler(ActionContext actionContext, String key, String title, JSONArray datasets) {
        if (datasets == null || datasets.isEmpty()) return;
        String accDataSet = datasets.getString(0);
//        logger.info("accDataSet :   " + accDataSet);
        String sbAccUrl = "http://sbcx.pcyyhj.zjzwfw.gov.cn/proxy/services/BizData/" + key + "?dataset=" + accDataSet + "&_t=" + System.currentTimeMillis();
        logger.info("sbAccUrl = " + sbAccUrl);
        Request request = new Request.Builder()
                .get()
                .url(sbAccUrl)
                .header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36")
                .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
                .build();
        String retStr = client.doGetRequest(sbAccUrl,map);
        parse(title,retStr,accDataSet);
        FileUtils.save(title, retStr);
        for (int i = 1; i < datasets.size(); i++) {
            String dataset = datasets.getString(i);
//            logger.info("dataset :  " + dataset);
            if (dataset.contains("_jg") || dataset.contains("tx")) {
                continue;
            }
            if (dataset.contains("jf")) {
                String flowUrl = "http://sbcx.pcyyhj.zjzwfw.gov.cn/proxy/services/BizData/" + key + "?dataset=" + dataset + "&_t=" + System.currentTimeMillis() +
                        "&order=asc&limit=" + LIMIT + "&offset=0&pageNo=1&pageSize=" + LIMIT + "&_=" + System.currentTimeMillis();
                String sbFlow = client.doGetRequest(flowUrl,map);
//                zheJiangZWService.parseAccount(sbContext);
                parse(title,sbFlow,dataset);
                FileUtils.save(title + "Flow", sbFlow);
            }
            if (dataset.contains("zh")) {
                String balanceUrl = "http://sbcx.pcyyhj.zjzwfw.gov.cn/proxy/services/BizData/" + key + "?dataset=" + dataset + "&_t=" + System.currentTimeMillis() +
                        "&order=asc&limit=" + LIMIT + "&offset=0&pageNo=1&pageSize=" + LIMIT + "&_=" + System.currentTimeMillis();
                String balance = client.doGetRequest(balanceUrl,map);
                parse(title,balance,dataset);
                FileUtils.save(title + "Balance", balance);
            }
            if (dataset.contains("xx")) {
                String accUrl = "http://sbcx.pcyyhj.zjzwfw.gov.cn/proxy/services/BizData/" + key + "?dataset=" + dataset + "&_t=" + System.currentTimeMillis() +
                        "&order=asc&limit=" + LIMIT + "&offset=0&pageNo=1&pageSize=" + LIMIT + "&_=" + System.currentTimeMillis();
                String acc = client.doGetRequest(accUrl,map);
                parse(title,acc,dataset);
                FileUtils.save(title + "xx", acc);
            }

        }
    }
    private void parse(String title,String retStr,String dataset){
        sbContext.setContent(retStr);
        sbContext.setFileName(title);
        if (dataset.contains("_jg") || dataset.contains("tx")) {
            return;
        }else  if (dataset.contains("sbcx_yllncbjbxx")){//个人基本信息
            zheJiangZWService.parseAccount(sbContext);
        }else if (dataset.contains("jf")){//流水
            zheJiangZWService.parseFlow(sbContext);
        }else if (dataset.contains("sbcx_ybzh")){//医疗账户
            zheJiangZWService.parseMedicardBalance(sbContext);
        }else if (dataset.contains("sbcx_ybjzxx")){//医保消费
            zheJiangZWService.parseConsume(sbContext);
        }else if (dataset.contains("sbcx_ylzh")||dataset.contains("sbcx_cjylzh")){
            zheJiangZWService.parseAnnualAccount(sbContext);
        }else if (dataset.contains("xx")){
            zheJiangZWService.parseInsurance(sbContext);
        }
    }
    /**
     * 解析出要爬取的种类
     *
     * @param retStr 页面
     * @return
     */
    private JSONArray getEntrys(String retStr) {
        JSONArray jsonArray = new JSONArray();
        Document parse = Jsoup.parse(retStr);
        parse.select(".sbcx-result > div").forEach(div -> {
            JSONObject jsonObject = new JSONObject();
            String key = div.attr("data-appkey").toString().trim();
            String title = div.select(".sbcx-result-header").text().trim();
            List dataset = div.select("table").eachAttr("data-dataset");
            jsonObject.put("key", key);
            jsonObject.put("title", title);
            jsonObject.put("dataset", dataset);
            jsonArray.add(jsonObject);
        });
        return jsonArray;
    }
    /**
     * 获取图片验证码
     *
     * @return
     */
    @Override
    public byte[] getCaptcha() {
        Request request = new Request.Builder()
                .get()
                .url("https://puser.zjzwfw.gov.cn/sso/usp.do?action=verifyimg&type=1&rd=%27+Math.random()+%27&t=" + Math.random())
                .header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36")
                .header("Accept", "image/webp,image/apng,image/*,*/*;q=0.8")
                .header("Referer", "https://puser.zjzwfw.gov.cn/sso/usp.do?action=ssoLogin&servicecode=njdh")
                .build();
        return client.request1(request);
    }

    /**
     * 浙江政务网服务密码加密
     *
     * @param str
     * @return
     * @throws Exception
     */
    public String encode(String str, String key) throws Exception {
        String url = ZheJiangZW.class.getClassLoader().getResource("conf/ZheJiangZW.html").getPath();
        HtmlPage htmlPage = WEBCLIENT.getPage("file://" + url);
        ScriptResult t = htmlPage.executeJavaScript("encode(\"" + str + "\",\"" + key + "\")", "injected script", 500);
        return t.getJavaScriptResult().toString();
    }

    @Override
    public Result crawler(ActionContext actionContext) {
        Result result = new Result();
        result.setSuccess(Result.FAIL);
        result.setErrorCode(StateCodeEnum.STATE_CODE_403.getCode());
        if (actionContext == null || actionContext.isEmpty()) {
            result.setErrorMsg("网络错误");
            return result;
        }
        if ("login".equals(actionContext.getMethod())) {
            logger.info("[开始登录] ");
            String retStr = login(actionContext);
//            String retStr = actionContext.getCityCode();
//            result.setErrorCode(retStr);
            if ("0".equals(retStr)) {
                logger.info("[登录成功] ");
//                CallBack.loginSuccess(actionContext.getUser(),"HangZhou");
                this.asyncTaskService.executeAsyncTask(this,actionContext);
                result.setSuccess(Result.SUCCESS);
                result.setErrorCode(StateCodeEnum.STATE_CODE_200.getCode());
                result.setErrorMsg("ok");
            } else if ("-4".equals(retStr) || "-5".equals(retStr)) {
                result.setErrorCode("-1");
                result.setErrorMsg("验证码错误");
                logger.info("验证码错误,msg:"+retStr);
            } else if ("-998".equals(retStr)) {
                result.setErrorMsg("请升级为高级实名认证用户，再使用本服务");
                logger.info("请升级为高级实名认证用户，再使用本服务,msg:"+retStr);
            } else if ("-2".equals(retStr)) {
                result.setErrorMsg("错误的业务系统");
                logger.info("错误的业务系统,msg:"+retStr);
            } else if ("-3".equals(retStr)) {
                result.setErrorMsg("无权访问业务系统");
                logger.info("无权访问业务系统,msg:"+retStr);
            } else if ("-1".equals(retStr)){
                result.setErrorMsg("无权访问业务系统");
                logger.info("无权访问业务系统,msg:"+retStr);
            } else {
                result.setErrorMsg(retStr);
                logger.info("网络错误,msg:"+retStr);
            }
        }else {
            result.setErrorMsg("无效请求");
            logger.info("无效请求");
        }
        return result;
    }
}
